<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h1>demo</h1>
  <img src="./weakMap数据结构.png" alt="">
  <script>
// 保存当前需要收集的响应式函数
let activeReactiveFn = null
// 首先  
let obj={
  name:'ys',
  age:18,
};
// debugger
// 构建一个 类 来收集方法
// 但是 什么时候 开始收集呢 第一次 绑定时开始收集
class Depend{
  constructor(){
    this.reactiveFns=new Set()
  }
// 收集方法
  depend(){
    if(activeReactiveFn){
      this.reactiveFns.add(activeReactiveFn)
    }
  }
  // 执行方法
  notify(){
    this.reactiveFns.forEach(fu=>{
      fu()
    })
  }

}

// 因为要保存的方法可能会很多，扩展数据解构 封装一个获取depend 函数

  // 这里是创建一个 targetmap 目的是收集 变量 和使用变量的方法

  // WeakMap 的设计目的在于，键名是对象的弱引用（垃圾回收机制不将该引用考虑在内），所以其所对应的对象可能会被自动·回收，当对象被回收后，WeakMap 自动移除对应的键值对。
// 典型应用是，一个对应 DOM 元素的 WeakMap 结构，当某个 DOM 元素被清除，其所对应的 WeakMap 记录就会自动被移除。
const targetMap = new WeakMap()
// 这里使用 WeakMap的新map 格式的 优势是
// 1 WeakMap 只接受对象作为键名（null除外），而且键名所指向的对象，不计入垃圾回收机制
// 
function getDepend(target,key){
  // 第一次 在 targetMap 里找这个对象 对应的map 没有·就创建一个这个对象的map
  // 数据解构 是个 map 格式的 key 是这个对象 value 是一个新的map对象 
  let map = targetMap.get(target)
  if(!map){
    map = new Map()
    console.log("map",map);
    targetMap.set(target,map)
    console.log("targetMap",targetMap);
  }
  // 这一步是找到了 对象的 WeakMap数据之后，开始取里面的数据方法了
  let depend = map.get(key)
  if(!depend){
    depend = new Depend(key)
    map.set(key,depend)
    console.log("map",map);
   
  }
  return depend
}

// 这个方法实现的是 方法监听
function watchFn(fu){
  console.log(12345);
   activeReactiveFn = fu
  fu()
  activeReactiveFn  = null
}

// 开创建 修改数据的 解构
function reactive(obj){
 return new Proxy(obj,{
  get:function(target,key,receiver){
    // console.log(target,"target",key,"key");

    const depend = getDepend(target,key)
    depend.depend()
    return Reflect.get(target, key, receiver)
  },
  set:function(target,key,newValue,receiver){
    // console.log(target,"target",key,"key");
    // 用 reflect 主要是 修改 我们new 出来的Proxy 对象 而不是去修改 obj对象
    Reflect.set(target,key,newValue,receiver)
    const depend = getDepend(target,key)
    depend.notify()
  }
  
 })   
}


console.log(456);
// 当我在这里修改age时 其他地方的age 也都要跟着被修改
// obj.age=20

const proxyObj = reactive({name:'ys',age:18})
// proxyObj.age=21

function logAges(){
  console.log(proxyObj.age,"obj.age");
}
function addAge(){
  console.log(proxyObj,proxyObj.age,'obj.age');
  // proxyObj.age = 19
}
watchFn(addAge);
watchFn(logAges)
console.log(proxyObj.age);
proxyObj.age = 22
proxyObj.name='yy'
console.log("proxyObj",proxyObj);
  </script>
</body>
</html>